本來想要趁這幾天多做一些Vue的改寫,跟原生JS版同步,但時間上蠻趕的,又遇上一些難題。因此這幾天先以原生JS版為主。可以預期到了第三十天鐵人賽結束,Vue版本應該沒辦法同步完成。但這個系列的文章會持續到Vue版本開發完才會結束。
預期效果
從unsplash api取得隨機圖片,渲染到一個方塊中,然後再拖曳到另一個空白的方塊中來填滿。拼圖遊戲應該會用到類似的效果。
請大家先來看CodePen:
https://codepen.io/zyrxdkoz/pen/MWomYzG
實作邏輯
html部分
<div class="empty">
// 啟用draggable屬性,是true的話就可以拖曳圖片
<div class="fill" draggable="true"></div>
</div>
<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>
css部分
.empty {
height: 150px;
width: 150px;
margin: 10px;
border: solid 3px black;
background: white;
}
.fill {
// 使用unsplash api
background-image: url('https://source.unsplash.com/random/150x150');
background-size: cover;
height: 145px;
width: 145px;
cursor: pointer;
}
.hold {
border: solid 5px #ccc;
}
.hovered {
background-color: #333;
border-color: white;
border-style: dashed;
}
@media (max-width: 800px) {
body {
flex-direction: column;
}
}
javascript部分
const fill = document.querySelector('.fill')
const empties = document.querySelectorAll('.empty')
// 在有fill選擇器的div放上監聽器
// ''當中的名稱都是DOM API預設好的行為,行為發生後就啟動相關連的函式
fill.addEventListener('dragstart', dragStart)
fill.addEventListener('dragend', dragEnd)
// 迭代陣列中每個屬性的值
for(const empty of empties) {
empty.addEventListener('dragover', dragOver)
empty.addEventListener('dragenter', dragEnter)
empty.addEventListener('dragleave', dragLeave)
empty.addEventListener('drop', dragDrop)
}
function dragStart() {
// 當div被拖曳的時候,加上hold屬性(會出現灰白邊框)
this.className += ' hold'
// 同時也要將div改成白色,但為了避免與hold發生同步衝突,因此使用非同步語法setTimeout來加上invisible選擇器。
setTimeout(() => this.className = 'invisible', 0)
}
function dragEnd() {
// 停止拖曳行為後,加回fill選擇器
this.className = 'fill'
}
function dragOver(e) {
// 停止瀏覽器預設行為:拒絕透過拖曳來執行submit
e.preventDefault()
}
function dragEnter(e) {
// 停止瀏覽器預設行為:拒絕透過拖曳來執行submit
e.preventDefault()
// 當拖曳圖片滑過任一個<div>時,加上hovered選擇器
this.className += ' hovered'
}
function dragLeave() {
// 當拖曳圖片滑過並離開任一個<div>時,將該<div>的class指定為empty。
this.className = 'empty'
}
function dragDrop() {
// 清空hovered選擇器
this.className = 'empty'
// 拖曳到<div>後放掉,即是dragDrop行為,
// 此時在<div>當中加入child dom,也就是div.full
this.append(fill)
}